package com.mian.server;

import com.mian.annotation.RemoteService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


// 没有这个注解 不会执行接口BeanPostProcessor的方法？？？？？
@Component
public class NettyServer implements ApplicationListener<ContextRefreshedEvent>, BeanPostProcessor {

	// key=接口名称， value=实现类对象
	private Map<String, Object> handlerMap = new HashMap<>();

	public void start() {
		EventLoopGroup parentGroup = new NioEventLoopGroup();
		EventLoopGroup childGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(parentGroup, childGroup);
			bootstrap.option(ChannelOption.SO_BACKLOG, 128)
					.childOption(ChannelOption.SO_KEEPALIVE, false)
					.channel(NioServerSocketChannel.class)
					.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
						@Override
						public void initChannel(SocketChannel ch) throws Exception {
							ch.pipeline().addLast(new DelimiterBasedFrameDecoder(65535, Delimiters.lineDelimiter()[0]));

							ch.pipeline().addLast(new StringDecoder());
							ch.pipeline().addLast(new StringEncoder());
							// 读超时 写超时：
							// 在服务器端每个 readerIdTime 秒来检查一下channelRead方法被调用，
							// 如果在 readerIdTime内 该链上的channelRead方法都没有被触发，就会调用userEventTriggered
//							ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
							ch.pipeline().addLast(new NettyServerHandler(handlerMap));

						}
					});

			ChannelFuture f = bootstrap.bind(8080).sync();

			// 关闭RPC服务器
			f.channel().closeFuture().sync();

		} catch (Exception e) {
			e.printStackTrace();
			parentGroup.shutdownGracefully();
			childGroup.shutdownGracefully();
		}

	}

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	// bean 为注入到spring容器中的bean
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

		// 被 RemoteService 注解的类
		// 赞不支持一个接口多个实现类的情况咯
		if (bean.getClass().isAnnotationPresent(RemoteService.class)){
			handlerMap.put(bean.getClass().getInterfaces()[0].getName(), bean);

		}
		return bean;
	}

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		this.start();
	}

}
